package com.example.spring.code.a06;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

/**
 * Aware 接口及 InitializingBean 接口
 */
public class A06Application {

    private static final Logger log = LoggerFactory.getLogger(A06Application.class);

    public static void main(String[] args) {
        /*
            1. Aware 接口用于注入一些与容器相关信息，例如
                a. BeanNameAware 注入 bean 的名字
                b. BeanFactoryAware 注入 BeanFactory 容器
                c. ApplicationContextAware 注入 ApplicationContext 容器
                d. EmbeddedValueResolverAware ${}

            2. b、c、d 的功能用 @Autowired 注解也可以实现，为什么还需要使用 Aware 接口呢？
            简单来说：
                a. @Autowired 的解析需要用到 bean 后处理器，属于扩展功能
                b. 而 Aware 接口属于内置功能，不加任何扩展，Sping 就能识别
            某些情况下，扩展功能会失效，但内置功能不会失效

            例1：GenericApplicationContext 中默认没有bean后处理器，此时 @Autowired 和 @PostConstruct 注解无效，但是 Aware 接口仍然可以发挥作用
                当加上两种 Bean 后处理器后，@Autowired、@PostConstruct 注解就可以生效了

            例2：Java 配置类中添加了 bean 工厂后处理器后，Aware 接口方式的注入和初始化仍然成功，而 @Autowired 注解和 @PostConstruct 注解是无效的

         */
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);
        context.registerBean("myConfig1", MyConfig1.class);
        context.registerBean("myConfig2", MyConfig2.class);
        // ⬇️加上下面这两个后处理器，注解才会生效
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh(); // 1. beanFactory 后处理器 2. 添加 bean 后处理 3. 初始化所有单例
        context.close();


        /*
            学到了什么：
                a. Aware 接口提供了一种【内置】的注入手段，可以注入 BeanFactory、ApplicationContext、BeanName 等
                b. InitializingBean 接口提供了一种【内置】的初始化手段
                c. 内置的注入和初始化不受扩展功能的影响，总会被执行，因此 Spring 框架内部的类常用它们
         */
    }

}
